#include <iostream>
#include <unistd.h>
#include <assert.h>
#include <string.h> // strerror
#include <fcntl.h>
#include <sys/socket.h>

#include "Sunnet.h"
#include "SocketWorker.h"

using namespace std;

void SocketWorker::Init() {
    cout << "Socket Worker Init" << endl;

    epollfd = epoll_create(1024);
    assert(epollfd > 0);
}

void SocketWorker::operator()() {
    const int EVENT_SIZE = 64;
    struct epoll_event events[EVENT_SIZE];
    while (true) {
        int eventCount = epoll_wait(epollfd, events, EVENT_SIZE, -1);

        for (int i = 0; i < eventCount; i++) {
            epoll_event ev = events[i];
            OnEvent(ev);
        }
    }
}

void SocketWorker::AddEvent(int fd) {
    cout << "Add Event " << fd << endl; 
    struct epoll_event ev;
    ev.events = EPOLLIN | EPOLLET; // EPOLLHUP, EPOLLPRI, EPOLLERR
    ev.data.fd = fd; 
    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
        cout << "epoll_ctl add failed : " << strerror(errno) << endl;
    }
}

void SocketWorker::RemoveEvent(int fd) {
    cout << "Del Event " << fd << endl; 
    epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, NULL);
}

void SocketWorker::ModifyEvent(int fd, bool epollOut) {
    cout << "Modify Event " << fd << " " << epollOut << endl; 
    struct epoll_event ev;
    ev.data.fd = fd;
    ev.events = EPOLLIN | EPOLLET; 
    if (epollOut) ev.events |= EPOLLOUT;
    epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &ev);
}

void SocketWorker::OnEvent(epoll_event ev) {
    cout << "OnEvent" << endl; 
    int fd = ev.data.fd;
    auto conn = Sunnet::instance->GetConn(fd);
    if (conn == NULL) {
        cout << "Conn Get Error" << endl;
        return ;
    }
    // 事件类型
    bool isRead = ev.events & EPOLLIN;
    bool isWrite = ev.events & EPOLLOUT;
    bool isError = ev.events & EPOLLERR;

    // 监听socket -> listenfd
    if (conn->type == Conn::TYPE::LISTEN) {
        if (isRead) {
            OnAccept(conn);
        }
    } 
    // 普通socket -> clientfd
    else {
        if (isRead || isWrite) {
            OnRW(conn, isRead, isWrite);
        }
        if (isError) {
            cout << "OnError fd: " << conn->fd << endl;
        }
    }
}

void SocketWorker::OnAccept(shared_ptr<Conn> conn) {
    cout << "OnAccept" << endl; 
    int clientfd; // listenfd监听返回客户端fd
    if ((clientfd = accept(conn->fd, NULL, NULL)) < 0) {
        cout << "accept error" << endl;
        return ;
    }
    fcntl(clientfd, F_SETFL, O_NONBLOCK);
    Sunnet::instance->AddConn(clientfd, conn->serviceId, Conn::TYPE::CLIENT); // 添加连接对象
    AddEvent(clientfd);
    auto msg = make_shared<SocketAcceptMsg>();
    msg->type = BaseMsg::TYPE::SOCKET_ACCEPT;
    msg->listenfd = conn->fd;
    msg->clientfd = clientfd;
    Sunnet::instance->Send(conn->serviceId, msg);

    // unsigned long buffSize = 4294967295 // 4G
    // setsocketopt(clientfd, SOL_SOCKET, SO_SNDBUFFORCE, &buffSize, sizeof(buffSize)); // 设置更大的写缓冲区
}

void SocketWorker::OnRW(shared_ptr<Conn> conn, bool r, bool w) {
    cout << "OnRW" << endl; 
    auto msg = make_shared<SocketRWMsg>();
    msg->type = BaseMsg::TYPE::SOCKET_RW;
    msg->fd = conn->fd;
    msg->isRead = r;
    msg->isWrite = w;
    Sunnet::instance->Send(conn->serviceId, msg);
}

